#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "params.h"
#include "types.h"
#include "defs.h"
#include "parser.h"
#include "jitcc.h"
#include "runtime.h"

#define ASSERT(fmt,msg...)  {printf ("Runtime message:",##msg); printf (fmt,##msg); exit(EXIT_FAILURE);}

struct runtime * rtscratch;

struct dataseg *
getdataseg () {
    struct dataseg * ds;
    ds = (struct dataseg *) malloc (sizeof (struct dataseg));
    bzero (ds,sizeof (struct dataseg));
    ds->sz = DS_HEAPSZ;
    ds->heap = ds->mem;
    ds->stack = ds->mem + DS_HEAPSZ;
    return ds;
}

struct runtime *
getrt (struct textseg * ts, struct dataseg * ds, struct jitngin * jit ,struct varh * vh) {
    struct runtime * rt;
    rt = (struct runtime *) malloc (sizeof (struct runtime));
    if (!ts || !jit || !ds || !rt || !vh) 
        goto error;
    
    bzero (rt,sizeof (struct runtime));
    rt->jit = jit;
    rt->data = ds;
    rt->text = ts;
    rt->varheap = vh;
    rtscratch = rt;
    return rt;
    error:
    free (rt);
    return NULL;
}

#define FP (((uint64*)regs)[X_FP])
#define VSTKP (FP+inst->v->stackoff) // 指向栈中变量的指针
#define VHEAP (inst->v->heapaddr) // 指向堆中变量的指针
#define VTYPE (inst->v->type)
#define VSIZE (inst->v->sz)

int // 释放所有局部变量(一般只记录栈中引用变量)
freeallvar (void * regs) {
    struct var ** v;
    for (v=rtscratch->stkvar.v;v<rtscratch->stkvar.v+rtscratch->stkvar.len;v++) {
        if (((*v)->flg & F_VAR_VALID) && 
            ((*v)->type == VAR_SPACE || (*v)->type == VAR_STR)){
            if (((*v)->flg & F_VAR_STACK)) {
                varfree (rtscratch->varheap, (void*)(FP+(*v)->stackoff));
                (*v)->type = VAR_UNDEF;
            }
        }
    }
    rtscratch->stkvar.len = 0;
    bzero (rtscratch->stkvar.v, sizeof (rtscratch->stkvar.v));
    return 0;
}

int // runtime stack是否存在var?
rtstkhasvar (struct var *v) {
    struct var ** vp = rtscratch->stkvar.v;
    for (;vp<vp+rtscratch->stkvar.len;vp++){
        if (*vp == v) return 1;
    }
    return 0;
}

uint64
ecall_getc (uint64 a0, uint64 a1) {
    (void) a0;
    (void) a1;
    //printf ("a0:%lld\n",a0);
    int c;
    c = getchar ();
    return (uint64)c;
}

uint64
ecall_getint (uint64 a0, uint64 a1) {
    (void) a0;
    (void) a1;
    int64 i;
    scanf ("%lld\n",&i);
    return (uint64)i;
}

uint64
ecall_printc (uint64 a0, uint64 a1) {
    (void) a0;
    (void) a1;
    int c;
    c = a0;
    printf ("%c",c);
    return 0;
}

uint64
ecall_printint (uint64 a0, uint64 a1) {
    (void) a0;
    (void) a1;
    int64 i;
    i = a0;
    printf ("%lld\n",i);
    return 0;
}

uint64
ecall (uint64 v, uint64 a0, uint64 a1) {
    #define ECALL_GETC 0
    #define ECALL_GETINT 1
    #define ECALL_PRINTC 3
    #define ECALL_PRINTINT 4
    switch (v) {
        case ECALL_GETC : {
            return ecall_getc (a0, a1);
            break;
        }
        case ECALL_GETINT : {
            return ecall_getint (a0, a1);
            break;
        }
        case ECALL_PRINTC : {
            return ecall_printc (a0, a1);
            break;
        }
        case ECALL_PRINTINT : {
            return ecall_printint (a0, a1);
            break;
        }
    }
    return ERROR;
}

int
assignvar (void * regs, struct ins * inst) {
    #define IMM (inst->asgn.imm)
    void * newv;
    if (!(inst->v->flg&F_VAR_VALID))
        goto error;
    if ((inst->v->flg&F_VAR_STACK)) {
        if (inst->v->type == VAR_STR || inst->v->type == VAR_SPACE) {
            varfree (rtscratch->varheap, (void*)VSTKP); // 释放原指针
        }
        switch (inst->asgn.type) {
            case VAR_I8 : {
                *((uint64*)VSTKP) = (int64)((int8)IMM);
                VTYPE = VAR_I8;
                VSIZE = 8;
                break;
            }
            case VAR_I16 : {
                *((uint64*)VSTKP) = (int64)((int16)IMM);
                VTYPE = VAR_I16;
                VSIZE = 8;
                break;
            }
            case VAR_I32 : {
                *((uint64*)VSTKP) = (int64)((int32)IMM);
                VTYPE = VAR_I32;
                VSIZE = 8;
                break;
            }
            case VAR_I64 : {
                *((uint64*)VSTKP) = (int64)((int64)IMM);
                VTYPE = VAR_I64;
                VSIZE = 8;
                break;
            }
            case VAR_U8 : {
                *((uint64*)VSTKP) = (uint64)((uint8)IMM);
                VTYPE = VAR_U8;
                VSIZE = 8;
                break;
            }
            case VAR_U16 : {
                *((uint64*)VSTKP) = (uint64)((uint16)IMM);
                VTYPE = VAR_U16;
                VSIZE = 8;
                break;
            }
            case VAR_U32 : {
                *((uint64*)VSTKP) = (uint64)((uint32)IMM);
                //printf ("asgn:%lld\n",*((uint64*)VSTKP));
                VTYPE = VAR_U32;
                VSIZE = 8;
                break;
            }
            case VAR_U64 : {
                *((uint64*)VSTKP) = (uint64)((uint64)IMM);
                VTYPE = VAR_U64;
                VSIZE = 8;
                break;
            }
            case VAR_STR : {
                newv = varalloc (rtscratch->varheap, strlen (inst->asgn.str));
                if (newv == NULL) goto error;
                strcpy (newv, inst->asgn.str); // 赋值新变量
                *((uint64*)VSTKP) = (uint64)newv; // 更新指针
                VTYPE = VAR_STR;
                VSIZE = strlen (inst->asgn.str);
                if (!rtstkhasvar (inst->v))
                    rtscratch->stkvar.v[rtscratch->stkvar.len++] = inst->v; // 记录运行时栈中引用变量 ! 注意,需要确保只记录一次
                break;
            }
            case VAR_SPACE : {
                newv = varalloc (rtscratch->varheap, inst->asgn.space);
                if (newv == NULL) goto error;
                *((uint64*)VSTKP) = (uint64)newv; // 更新指针
                VTYPE = VAR_SPACE;
                VSIZE = inst->asgn.space;
                if (!rtstkhasvar (inst->v))
                    rtscratch->stkvar.v[rtscratch->stkvar.len++] = inst->v; // 记录运行时栈中引用变量 ! 注意,需要确保只记录一次
                break;
            }
            default : {
                goto error;
                break;
            }
        }
        goto success;
    } else if ((inst->v->flg&F_VAR_HEAP)) {
        if (inst->v->type == VAR_STR || inst->v->type == VAR_SPACE) {
            varfree (rtscratch->varheap, VHEAP); // 释放原指针
        }
        switch (inst->asgn.type) {
            case VAR_I8 : {
                *((uint64*)VHEAP) = (int64)((int8)IMM);
                VTYPE = VAR_I8;
                VSIZE = 8;
                break;
            }
            case VAR_I16 : {
                *((uint64*)VHEAP) = (int64)((int16)IMM);
                VTYPE = VAR_I16;
                VSIZE = 8;
                break;
            }
            case VAR_I32 : {
                *((uint64*)VHEAP) = (int64)((int32)IMM);
                VTYPE = VAR_I32;
                VSIZE = 8;
                break;
            }
            case VAR_I64 : {
                *((uint64*)VHEAP) = (int64)((int64)IMM);
                VTYPE = VAR_I64;
                VSIZE = 8;
                break;
            }
            case VAR_U8 : {
                *((uint64*)VHEAP) = (uint64)((uint8)IMM);
                VTYPE = VAR_U8;
                VSIZE = 8;
                break;
            }
            case VAR_U16 : {
                *((uint64*)VHEAP) = (uint64)((uint16)IMM);
                VTYPE = VAR_U16;
                VSIZE = 8;
                break;
            }
            case VAR_U32 : {
                *((uint64*)VHEAP) = (uint64)((uint32)IMM);
                VTYPE = VAR_U32;
                VSIZE = 8;
                break;
            }
            case VAR_U64 : {
                *((uint64*)VHEAP) = (uint64)((uint64)IMM);
                VTYPE = VAR_U64;
                VSIZE = 8;
                break;
            }
            case VAR_STR : {
                newv = varalloc (rtscratch->varheap, strlen (inst->asgn.str));
                if (newv == NULL) goto error;
                strcpy (newv, inst->asgn.str); // 赋值新变量
                *((uint64*)VHEAP) = (uint64)newv; // 更新指针
                VTYPE = VAR_STR;
                VSIZE = strlen (inst->asgn.str);
                break;
            }
            case VAR_SPACE : {
                newv = varalloc (rtscratch->varheap, strlen (inst->asgn.str));
                if (newv == NULL) goto error;
                *((uint64*)VHEAP) = (uint64)newv; // 更新指针
                VTYPE = VAR_SPACE;
                VSIZE = inst->asgn.space;
                break;
            }
            default : {
                goto error;
                break;
            }
        }
        goto success;
    }
    error:
    return ERROR;
    success:
    return SUCCESS;
}

void
installtb (struct ins * i, struct transblock * tb) {
    i->tb = tb;
    i->flg |= F_INS_TB;
}

int
ignite (struct runtime * rt) {
    struct jitngin * jit;
    struct transblock * tb;
    struct textseg * ts;
    struct ins * ir; 
    uint64 regs[X_NUM];
    bzero (regs, sizeof (regs));
    *((uint64*)(rt->data->stack)) = rt->text->end; // 最后一个指令 (END)
    *((uint64*)(rt->data->stack + 8)) = (uint64)rt->data->stack; // 第0个栈帧
    regs[X_FP] = (uint64)(rt->data->stack+16); // 新栈帧
    regs[X_PC] = 0;
    ts = rt->text;
    jit = rt->jit;
    rt->regs = regs;
    /* 注:parser中已将带.begin标签的指令放到了第0个指令位置 */
    for (;;) {
        if (regs[X_PC] >= ts->sz) // 越界
            goto error;
        ir = ts->insls + regs[X_PC]; // 当前指令指针
        if (ir->type == INS_END)
            break;
        if(!(ir->flg & F_INS_VALID)) // 指令无效
            goto error;
        if (ir->flg & F_INS_TB) { // TB块已生成
            jitexec (regs, ir);
            goto executed;
        }
        if(ir->flg & F_INS_RTC) { // 当前指令存在运行时控制属性
            if (ir->rtc == RTC_END) { // 这种情况不会出现
                rtexec (regs, ir);
                goto finish;
            } else if (ir->rtc == RTC_RT) { // 使用RUNTIME执行,将runtime模式切换到rt模式
                rt->mode = RUNTIME_RT;
                goto execute; // 跳转执行
            } else if (ir->rtc == RTC_JIT) { // 使用JIT执行,将runtime模式切换到jit模式
                rt->mode = RUNTIME_JIT;
                goto execute;
            } else {
                ASSERT ("非法标签");
            }
        }
        if (ir->execnt > NR_TRJIT) { // 该指令是热点,应该生成TB块
            tb = genjitblk (jit, regs[X_PC]);
            if (tb != NULL) { // tb块已生成
                installtb (ir, tb);
                jitexec (regs, ir);
                goto executed;
            }
            // tb块未生成,falldown
        }
        execute:
        if (rt->mode == RUNTIME_RT) {
            rtexec (regs, ir);
            ir->execnt++;
        } else if (rt->mode == RUNTIME_JIT) { // 使用JIT执行
            tb = genjitblk (jit, regs[X_PC]);
            if (tb != NULL) { // tb块已生成, 使用JIT模式运行
                installtb (ir, tb);
                jitexec (regs, ir);
                goto executed;
            }
            rtexec (regs, ir); // tb块未生成, 使用RT模式运行
        } else { // 默认使用RT模式运行
            rtexec (regs, ir);
            ir->execnt++;
        }
        executed:;
    }
    finish:
    return SUCCESS;
    error:
    return ERROR;
}